package com.ihr360.payroll.controller.salaryplan;

import com.google.common.collect.Lists;
import com.ihr360.commons.entity.AuthUserInfo;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.request.Ihr360SearchBody;
import com.ihr360.commons.specification.Ihr360Specification;
import com.ihr360.commons.utils.RestToReturnUtils;
import com.ihr360.entity.BasicStaffInfoEntity;
import com.ihr360.entity.BasicStaffInfoInSalaryPlanEntity;
import com.ihr360.maven.plugin.ModuleCodeStore;
import com.ihr360.maven.plugin.annotation.FunctionDefinition;
import com.ihr360.maven.plugin.annotation.ModuleDefinition;
import com.ihr360.payroll.model.dto.salary.plan.SalaryPlanStaff;
import com.ihr360.payroll.model.dto.salary.plan.config.PayslipConfig;
import com.ihr360.payroll.request.salaryPlanStaff.SalaryPlanStaffSearchBody;
import com.ihr360.payroll.request.salaryPlanStaff.SalaryPlanStaffSearchText;
import com.ihr360.payroll.service.payslip.PayslipConfigService;
import com.ihr360.payroll.service.salaryplan.SalaryPlanService;
import com.ihr360.payroll.service.salaryplan.SalaryPlanStaffService;
import com.ihr360.shared.basicstaffinfo.dto.SyncedBasicStaffInfo;
import com.ihr360.shared.basicstaffinfo.service.BasicStaffInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author tomtao
 */
@RestController
@RequestMapping("/salaryPlanStaff")
@ModuleDefinition(mainModuleCode = ModuleCodeStore.Module.SALARY_CODE,
        mainModuleName = ModuleCodeStore.Module.SALARY_NAME,
        subModuleCode = ModuleCodeStore.Module.Salary.SALARY_PLAN_CODE,
        subModuleName = ModuleCodeStore.Module.Salary.SALARY_PLAN_NAME)
public class SalaryPlanStaffController {

    @Autowired
    SalaryPlanService salaryPlanService;
    @Autowired
    SalaryPlanStaffService salaryPlanStaffService;
    @Autowired
    BasicStaffInfoService basicStaffInfoService;
    @Autowired
    PayslipConfigService payslipConfigService;

    @FunctionDefinition(functionName = "薪资方案添加员工", functionCode = ModuleCodeStore.Function.ADD)
    @PutMapping(value = "/joinStaffToPlan/{planId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void joinStaffToPlan(@PathVariable Long planId, @RequestBody List<String> staffIds) {
        List<SalaryPlanStaff> salaryPlanStaffList = new ArrayList<>();
        // 获取默认工资单
        PayslipConfig payslipConfig = salaryPlanService.getDefaultPayslipConfig(planId);
        Long payslipConfigId = payslipConfig != null ? payslipConfig.getId() : null;
        staffIds.forEach(staffId ->
                salaryPlanStaffList.add(new SalaryPlanStaff(planId, staffId, true, payslipConfigId, SalaryPlanStaff.StaffState.NORMAL))
        );
        salaryPlanStaffService.save(planId,salaryPlanStaffList);
        RestToReturnUtils.setMessage("添加成功！");
    }

    @FunctionDefinition(functionName = "修改薪资方案中员工的工资单信息", functionCode = ModuleCodeStore.Function.VIEW)
    @PutMapping(value = "/changePaySlipConfig", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void changePaySlipConfig(@RequestBody SalaryPlanStaff salaryPlanStaff) {
        salaryPlanStaffService.changePaySlipConfig(salaryPlanStaff.getSalaryPlanId(),
                salaryPlanStaff.getStaffId(), salaryPlanStaff.getPaySlipConfigId());
        RestToReturnUtils.setMessage("成功！");
    }

    @FunctionDefinition(functionName = "从薪资方案中删除员工", functionCode = ModuleCodeStore.Function.VIEW)
    @DeleteMapping(value = "/{planId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void delete(@PathVariable Long planId, @RequestBody List<String> staffIds) {
        salaryPlanStaffService.deleteSalaryPlanStaff(planId, staffIds);
        RestToReturnUtils.setMessage("删除成功！");
    }

    @FunctionDefinition(functionName = "分页获取薪资方案中员工", functionCode = ModuleCodeStore.Function.VIEW)
    @PostMapping(value = "/getPlanStaffPage", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Page<BasicStaffInfoInSalaryPlanEntity> getPlanStaffPage(@RequestParam Long planId,
                                                                   @RequestBody SalaryPlanStaffSearchBody<SyncedBasicStaffInfo> salaryPlanStaffSearchBody,
                                                                   AuthUserInfo authUserInfo) {
        Ihr360SearchBody<SyncedBasicStaffInfo> searchBody = salaryPlanStaffSearchBody.getSearchBody();
        SalaryPlanStaffSearchText salaryPlanStaffSearchText = salaryPlanStaffSearchBody.getSalaryPlanStaffSearchText();
        Specification<SyncedBasicStaffInfo> specification = searchBody.getSpecification();
        if(salaryPlanStaffSearchText != null
                && !CollectionUtils.isEmpty(salaryPlanStaffSearchText.getFieldNames())
                && StringUtils.isNotBlank(salaryPlanStaffSearchText.getSearchText())) {
            String searchText = salaryPlanStaffSearchText.getSearchText();
            List<String> fieldNames = salaryPlanStaffSearchText.getFieldNames();
            specification = (root, cq, cb) -> {
                ArrayList predicates = Lists.newArrayList();
                fieldNames.forEach(fieldName ->
                        predicates.add(cb.like(root.get(fieldName), "%" + searchText + "%"))
                );
                Predicate predicate = cb.or((Predicate[])predicates.toArray(new Predicate[predicates.size()]));
                if (searchBody.getSpecification() != null) {
                    return cb.and(predicate, searchBody.getSpecification().toPredicate(root, cq, cb));
                }
                return predicate;
            };
        }
        return salaryPlanStaffService.getStaffs4SalaryPlan(authUserInfo.getCompanyId(), planId, specification, searchBody.getPageable());
    }

    @FunctionDefinition(functionName = "分页获取账期中包含的员工", functionCode = ModuleCodeStore.Function.VIEW)
    @PostMapping(value = "/getPayPeriodStaff", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Page<BasicStaffInfoEntity> getPayPeriodStaffPage(@RequestParam Long planId,
                                                            @RequestBody Ihr360SearchBody<SyncedBasicStaffInfo> searchBody,
                                                            AuthUserInfo authUserInfo) {
        return salaryPlanStaffService.getStaffs4ActivePayPeriod(authUserInfo.getCompanyId(), planId,
                (Ihr360Specification<SyncedBasicStaffInfo>) searchBody.getSpecification(), searchBody.getPageable());
    }

    @FunctionDefinition(functionName = "分页获取 id在指定范围内的员工数据", functionCode = ModuleCodeStore.Function.VIEW)
    @PostMapping(value = "/getBasicStaffPageByIds", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Page<BasicStaffInfoEntity> getPayPeriodStaffPage(@RequestParam List<String> staffIdList,
                                                            @RequestBody Ihr360SearchBody<SyncedBasicStaffInfo> searchBody,
                                                            AuthUserInfo authUserInfo) {
        return basicStaffInfoService.getStaffsInclude(authUserInfo.getCompanyId(), staffIdList,
                (Ihr360Specification<SyncedBasicStaffInfo>) searchBody.getSpecification(), searchBody.getPageable());
    }

    @FunctionDefinition(functionName = "获取方案员工Id列表", functionCode = ModuleCodeStore.Function.VIEW)
    @GetMapping(value = "/getSalaryPlanStaffIdLst/{staffPlanId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public List<String> getSalaryPlanStaffIdLst(@PathVariable Long staffPlanId, @RequestParam(defaultValue = "false") boolean isPayPeriod) {
        List<Integer> staffStatusList = new ArrayList<>();
        if (isPayPeriod) {
            staffStatusList.add(SalaryPlanStaff.StaffState.NORMAL);
            staffStatusList.add(SalaryPlanStaff.StaffState.TEMP_ADD);
        } else {
            staffStatusList.add(SalaryPlanStaff.StaffState.NORMAL);
            staffStatusList.add(SalaryPlanStaff.StaffState.TEMP_REMOVE);
        }
        List<SalaryPlanStaff> staffIdList = salaryPlanStaffService.getListBySalaryPlanIdAndStaffStates(staffPlanId, staffStatusList);
        return staffIdList.stream().map(SalaryPlanStaff::getStaffId).collect(Collectors.toList());
    }
}
